﻿using System;
using System.Reflection;
using System.Xml;
using System.IO;
using System.Collections.Generic;
using System.Web;
using Grishko.DataTier;
using Grishko.DataTier.SqlSentence;
using System.Text;

namespace Grishko.SerilizeTools
{
    public class TypeMapItem:EntitySingle 
    {
        [EntityNonSerialized] 
        public string TagNameID { get{return ID; }  set{ID=value;} }
        public string AssemblyName { get; set; }
        public string TypeName { get; set; }
    }
    

    public class EntityActivator
    {
        private class TypeMapper
        {
            List<TypeMapItem> Source_ = null;

            public TypeMapper(Func<List<TypeMapItem>> Source)
            {
                Source_ = Source();
            }
            public Type GetType(string TagName)
            {
                foreach (var i in Source_)
                { 
                    if(i.TagNameID.ToUpper () .Equals (TagName .ToUpper ()))
                    {
                        if (string.IsNullOrEmpty(i.AssemblyName))
                            return MyGetType(i.AssemblyName, i.TypeName);
                        else
                            return MyGetType(i.TypeName);
                    }

                }
                return null;
            }
        }

        /// <summary>
        /// карта переоределения типов 
        /// </summary>
        public static Func<List<TypeMapItem>> MapSource;

        /// <summary>
        /// Create instance
        /// </summary>
        /// <param name="nd"></param>
        /// <returns></returns>
        public static object CreateInstance(XmlNode nd)
        {
            try
            {
                string a = nd.Attributes[SerilizeContext.AssemblyPref].Value;
                string s = nd.Attributes[SerilizeContext.TypePref].Value;                
                Type InstanceType = MyGetType(a, s);
                return CreateInstance(InstanceType);
            }
            catch (Exception ex)
            {
                throw new Exception(
                    "Не могу создать объект{0}", ex);
            }

        }

        /// <summary>
        /// Инстанцирует объект из строчки
        /// </summary>
        /// <param name="XmlStr"></param>
        /// <returns></returns>
        public static object CreateInstance(string XmlStr)
        {
            XmlDocument d = new XmlDocument();
            try
            {
                TextReader stringReader = new StringReader(XmlStr);
                XmlTextReader r = new XmlTextReader(stringReader);
                d.Load(r);
                if (null == d.FirstChild) return null;
                return CreateInstance(d.FirstChild);
            }
            finally
            {

            }
        }

        public static object CreateInstance_(string TypeName)
        {
            Type InstanceType = MyGetType(TypeName);
            object NewObj = null;

            if (TypeName.IndexOf("+") > -1)
                NewObj = Activator.CreateInstance(InstanceType);

            return NewObj;

        }

        public static object CreateInstance__(string TagName)
        {
            if (null == MapSource)
                return null;

            Type t = null;            
            TypeMapper m = new TypeMapper(MapSource);
            t = m.GetType(TagName);
            if (null == t)
                return null;

            return CreateInstance(t);

        }

        /// <summary>
        /// Инстанцировать объект. Если есть переопределение типа по ключу TagName - поднимается экземпляр соотв. переопределению
        /// если нет - тип переданный InstanceType
        /// </summary>
        /// <param name="TagName"></param>
        /// <param name="InstanceType"></param>
        /// <returns></returns>
        public static object CreateInstance(string TagName,Type InstanceType)
        {
            Type t = null;
            if (null == MapSource)
                return CreateInstance(InstanceType);
            
            TypeMapper m = new TypeMapper(MapSource);
            t=  m.GetType(TagName);

            if (null != t)
                return CreateInstance(t);

            return CreateInstance(InstanceType);
        }

        /// <summary>
        /// Инстанцировать объект. 
        /// </summary>
        /// <param name="TagName"></param>
        /// <param name="InstanceType"></param>
        /// <returns></returns>
        public static object CreateInstance(Type InstanceType)
        {
            object NewObj = null;
            if (InstanceType.ToString ().IndexOf("+") > -1)
                NewObj = Activator.CreateInstance(InstanceType);
            else
                NewObj = Activator.CreateInstance(InstanceType, null);

            return NewObj;

            
        }

        protected static Type MyGetType(string AssemblyName, string TypeName, string TagName)
        {
            Type t = null;
            if (null != MapSource)
            {
                TypeMapper m = new TypeMapper(MapSource);
                t = m.GetType(TagName);
                if (null != t)
                            return t;
            }


            Assembly a = GetAssembly(AssemblyName);
            if (null == a) return null;
            t = a.GetType(TypeName);
            return t;
        }

        protected static Type MyGetType(string AssemblyName, string TypeName)
        {
            Assembly a = GetAssembly(AssemblyName);
            if (null == a) return null;
            Type t = a.GetType(TypeName);
            return t;

        }

        /// <summary>
        /// Ищет тип во всех сборках текущего домена
        /// </summary>
        /// <param name="TypeName"></param>
        /// <returns></returns>
        protected static Type MyGetType(string TypeName)
        {
            foreach (Assembly a in AppDomain.CurrentDomain.GetAssemblies())

                foreach (Module m in a.GetModules())
                {
                    foreach (Type t in m.GetTypes())
                    {
                        if (t.ToString().Equals(TypeName)) return t;
                    }
                }
            return null;

        }
        //protected static Type MyGetType_(string TypeName)
        //{ 
        //    Type t = null;
        //    if (null != MapSource)                
        //        return MapSource.;

        //    return t; 

        //}



        protected static Assembly GetAssembly(string AssemblyName)
        {
            foreach (Assembly item in AppDomain.CurrentDomain.GetAssemblies())
            {
                if (item.ToString().Equals(AssemblyName)) return item;

            }
            return null;
        }

    }
}
